﻿using BCCommon;
using BCCommon.Enums;
using BCData.MakeStaticPagingComponent.PageTemplate;
using BCData.MakeStaticPagingComponent.PageTemplateAttachment;
using BCDto.Common.WebsiteConfiguration;
using BCEntity.MakeStaticPagingComponent.PageTemplate;
using BCService.Common.WebsiteConfigurationService;
using BCService.MakeStaticPagingComponent.WebsiteTemplateAttachmentService;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace BCService.MakeStaticPagingComponent.PageTemplateSerialize.HandleSaveFile
{
    public class HandleSaveFileService : IHandleSaveFileService
    {
        private readonly IConfiguration configuration;
        private readonly IWebsiteConfigurationService websiteConfigurationService;
        private readonly IWebsiteTemplateAttachmentService websiteTemplateAttachmentService;
        private readonly IPageTemplateAttachmentData pageTemplateAttachmentData;
        private readonly IPageTemplateData pageTemplateData;

        private WebsiteConfigurationDto WebsiteConfigurationDto { get; set; }
        private long? ContentId { get; set; }
        public HandleSaveFileService(IConfiguration configuration,
            IWebsiteConfigurationService websiteConfigurationService,
            IWebsiteTemplateAttachmentService websiteTemplateAttachmentService,
            IPageTemplateAttachmentData pageTemplateAttachmentData,
            IPageTemplateData pageTemplateData)
        {
            this.configuration = configuration;
            this.websiteConfigurationService = websiteConfigurationService;
            this.websiteTemplateAttachmentService = websiteTemplateAttachmentService;
            this.pageTemplateAttachmentData = pageTemplateAttachmentData;
            this.pageTemplateData = pageTemplateData;
        }

        #region 插入页面附件及构建head区域
        /// <summary>
        /// 插入页面附件及构建head区域
        /// </summary>
        /// <param name="pageTemplateEntity">页面模板信息</param>
        /// <param name="html">页面html</param>
        /// <returns></returns>
        public string SettingHeadAndAppendAttachments(PageTemplateEntity pageTemplateEntity, string html)
        {
            WebsiteConfigurationDto = this.websiteConfigurationService.Get();

            var websiteAttachments = this.websiteTemplateAttachmentService.GetList(pageTemplateEntity.WebsiteTemplateId);
            //开始处理页面附加文件信息
            var attachments = this.pageTemplateAttachmentData.GetList(pageTemplateEntity.PageTemplateId).Result;
            List<string> headCssList = new List<string>();
            List<string> headScriptList = new List<string>();
            List<string> footerCssList = new List<string>();
            List<string> footerScriptList = new List<string>();

            foreach (var item in websiteAttachments.Where(p => p.InsertLocation == StaticPageInsertLocationType.Head))
            {
                if (item.FileType == StaticPageFileType.Css)
                {
                    string css = string.Format("<link rel=\"stylesheet\" href=\"{0}\">", item.FileAddress);
                    headCssList.Add(css);
                }
                else
                {
                    string js = string.Format("<script type=\"text/javascript\" src=\"{0}\">", item.FileAddress);
                    headScriptList.Add(js);
                }
            }
            foreach (var item in websiteAttachments.Where(p => p.InsertLocation == StaticPageInsertLocationType.HtmlEnd))
            {
                if (item.FileType == StaticPageFileType.Css)
                {
                    string css = string.Format("<link rel=\"stylesheet\" href=\"{0}\">", item.FileAddress);
                    footerCssList.Add(css);
                }
                else
                {
                    string js = string.Format("<script type=\"text/javascript\" src=\"{0}\">", item.FileAddress);
                    footerScriptList.Add(js);
                }
            }
            foreach (var item in attachments.Where(p => p.InsertLocation == StaticPageInsertLocationType.Head))
            {
                if (item.FileType == StaticPageFileType.Css)
                {
                    string css = string.Format("<link rel=\"stylesheet\" href=\"{0}\">", item.FileAddress);
                    headCssList.Add(css);
                }
                else
                {
                    string js = string.Format("<script type=\"text/javascript\" src=\"{0}\">", item.FileAddress);
                    headScriptList.Add(js);
                }
            }
            foreach (var item in attachments.Where(p => p.InsertLocation == StaticPageInsertLocationType.HtmlEnd))
            {
                if (item.FileType == StaticPageFileType.Css)
                {
                    string css = string.Format("<link rel=\"stylesheet\" href=\"{0}\">", item.FileAddress);
                    footerCssList.Add(css);
                }
                else
                {
                    string js = string.Format("<script type=\"text/javascript\" src=\"{0}\">", item.FileAddress);
                    footerScriptList.Add(js);
                }
            }

            string htmlHeadTag = this.GetHtmlTag(html, "head");
            string title = string.Empty;
            List<string> metaList = new List<string>();
            List<string> linkList = new List<string>();
            List<string> scriptList = new List<string>();
            List<string> styleList = new List<string>();
            if (!string.IsNullOrWhiteSpace(htmlHeadTag))
            {
                title = GetHtmlTag(htmlHeadTag, "title");
                metaList = GetHtmlTags(htmlHeadTag, "meta");
                linkList = GetHtmlTags(htmlHeadTag, "link");
                scriptList = GetHtmlTags(htmlHeadTag, "script");
                styleList = GetHtmlTags(htmlHeadTag, "style");
            }
            if (!pageTemplateEntity.IsContentPage)
            {
                if (string.IsNullOrWhiteSpace(pageTemplateEntity.ParentPageCode))
                {
                    title = string.Format("{0}-{1}", pageTemplateEntity.PageName, WebsiteConfigurationDto.WebsiteName);
                }
                else
                {
                    title = string.Format("{0}-{1}-{2}", pageTemplateEntity.PageName, pageTemplateEntity.ParentPageName, WebsiteConfigurationDto.WebsiteName);
                }
            }
            else
            {
                title = string.Format("{0}-{1}", pageTemplateEntity.PageName, WebsiteConfigurationDto.WebsiteName);
            }
            List<string> newMetaList = new List<string>();
            if (!metaList.Any(p => p.IndexOf("charset=") > -1))
            {
                newMetaList.Add("<meta charset=\"utf-8\">");
            }
            if (!metaList.Any(p => p.IndexOf("name=\"viewport\"") > -1))
            {
                newMetaList.Add("<meta name=\"viewport\" content=\"width=device-width,initial-scale=1,maximum-scale=1\">");
            }
            if (!metaList.Any(p => p.IndexOf("name=\"keywords\"") > -1))
            {
                newMetaList.Add(string.Format("<meta name=\"keywords\" content=\"{0}\">", pageTemplateEntity.PageKeyword));
            }
            if (!metaList.Any(p => p.IndexOf("name=\"description\"") > -1))
            {
                newMetaList.Add(string.Format("<meta name=\"description\" content=\"{0}\">", pageTemplateEntity.PageDescription));
            }
            newMetaList.AddRange(metaList);
            List<string> pageCssList = new List<string>();
            List<string> pageScriptList = new List<string>();
            foreach (var item in linkList)
            {
                Regex regex = new Regex("href=\"([^\"]+)");
                if (regex.IsMatch(item))
                {
                    string src = regex.Match(item).Groups[1].ToString();
                    if (!headCssList.Any(p => p.IndexOf(src) > -1) && !pageCssList.Any(p => p.IndexOf(src) > -1))
                    {
                        pageCssList.Add(string.Format("<link rel=\"stylesheet\" href=\"{0}\">", src));
                    }
                }
                else
                {
                    pageCssList.Add(item);
                }
            }
            foreach (var item in scriptList)
            {
                Regex regex = new Regex("src=\"([^\"]+)");
                if (regex.IsMatch(item))
                {
                    string src = regex.Match(item).Groups[1].ToString();
                    if (!headScriptList.Any(p => p.IndexOf(src) > -1) && !pageScriptList.Any(p => p.IndexOf(src) > -1))
                    {
                        pageScriptList.Add(string.Format("<script type=\"text/javascript\" src=\"{0}\"></script>", src));
                    }
                }
                else
                {
                    pageScriptList.Add(item);
                }
            }
            for (int i = 0; i < headScriptList.Count; i++)
            {
                if (headScriptList[i].IndexOf("</script>") == -1)
                {
                    string value = string.Format("{0}</script>", headScriptList[i]);
                    headScriptList[i] = value;
                }
            }
            for (int i = 0; i < pageScriptList.Count; i++)
            {
                if (pageScriptList[i].IndexOf("</script>") == -1)
                {
                    string value = string.Format("{0}</script>", pageScriptList[i]);
                    pageScriptList[i] = value;
                }
            }

            StringBuilder newHtmlHeadTag = new StringBuilder("<head>");
            newHtmlHeadTag.Append("\r\n");
            newHtmlHeadTag.AppendJoin("\r\n", newMetaList);
            newHtmlHeadTag.Append("\r\n");
            newHtmlHeadTag.AppendLine(string.Format("<title>{0}</title>", title));
            newHtmlHeadTag.AppendJoin("\r\n", headCssList);
            newHtmlHeadTag.Append("\r\n");
            newHtmlHeadTag.AppendJoin("\r\n", pageCssList);
            newHtmlHeadTag.Append("\r\n");
            newHtmlHeadTag.AppendJoin("\r\n", headScriptList);
            newHtmlHeadTag.Append("\r\n");
            newHtmlHeadTag.AppendJoin("\r\n", pageScriptList);
            newHtmlHeadTag.Append("\r\n");
            newHtmlHeadTag.AppendLine("</head>");
            foreach (var item in styleList)
            {
                newHtmlHeadTag.AppendLine(item);
            }
            if (string.IsNullOrWhiteSpace(htmlHeadTag))
            {
                string preHead = html.Substring(0, html.IndexOf("<body>"));
                string afterHead = html.Substring(html.IndexOf("<body>"));
                html = preHead + newHtmlHeadTag.ToString() + afterHead;
            }
            else
            {
                html = html.Replace(htmlHeadTag, newHtmlHeadTag.ToString());
            }
            StringBuilder sb = new StringBuilder(html);
            foreach (string item in footerCssList)
            {
                sb.AppendLine(item);
            }
            foreach (string item in footerScriptList)
            {
                sb.AppendLine(item);
            }
            return sb.ToString();
        }
        #endregion

        #region 写入文件
        /// <summary>
        /// 获取父级页面路径
        /// </summary>
        /// <param name="pageTemplateEntity">页面模板信息</param>
        /// <returns></returns>
        public string GetParentPagePath(PageTemplateEntity pageTemplateEntity)
        {
            string path = string.Empty;

            if (pageTemplateEntity.PageLevel > 0)
            {
                path = this.pageTemplateData.GetParentAllPagePath(pageTemplateEntity.PageCode);
            }
            path = path.IndexOf("/") > -1 ? path.Substring(0, path.LastIndexOf("/")) : path;
            string directoryPath = string.Empty;
            DirectoryInfo directoryInfo = Directory.GetParent(Directory.GetCurrentDirectory());
            directoryPath = Path.Combine(directoryInfo.FullName, configuration["WebsiteName"]);
            directoryPath = Path.Combine(directoryPath, path);

            return directoryPath;
        }
        public void SaveHtml(string html, string path, int level, string fileName, int? index)
        {
            string filePath = path;
            string newFileName = fileName;

            if (this.ContentId.HasValue)
            {
                newFileName = string.Concat(fileName, "-", this.ContentId.ToString());
            }
            else if (index.HasValue && index.Value > 1)
            {
                newFileName = string.Concat(newFileName, "_", index.Value.ToString());
            }
            newFileName += ".html";
            string fullPath = Path.Combine(filePath, newFileName);
            if (!Directory.Exists(filePath))
            {
                Directory.CreateDirectory(filePath);
            }
            if (File.Exists(fullPath))
            {
                File.Delete(fullPath);
            }
            using (StreamWriter sw = new StreamWriter(fullPath, false))
            {
                sw.WriteLine(html);
                sw.Close();
            }
            if (this.ContentId.HasValue)
            {
                newFileName = fileName + ".html";
                fullPath = Path.Combine(filePath, newFileName);
                if (!Directory.Exists(filePath))
                {
                    Directory.CreateDirectory(filePath);
                }
                if (File.Exists(fullPath))
                {
                    File.Delete(fullPath);
                }
                using (StreamWriter sw = new StreamWriter(fullPath, false))
                {
                    sw.WriteLine(html);
                    sw.Close();
                }
            }
        }
        #endregion

        /// <summary>
        /// 提取页面Html标签代码块
        /// </summary>
        /// <param name="html">模板html</param>
        /// <param name="tag">html标签</param>
        /// <returns></returns>
        private string GetHtmlTag(string html, string tag)
        {
            Regex regex = new Regex($"(<{tag}>)([\\S\\s]*)(<\\/{tag}>)", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline);
            MatchCollection matchCollection = regex.Matches(html);

            string htmlHead = string.Empty;

            if (matchCollection.Count > 1)
            {
                throw new ArgumentException("一个页面仅应只有一个head标签区域!");
            }
            else if (matchCollection.Count == 1)
            {
                htmlHead = matchCollection[0].Groups[0].Value;
            }
            return htmlHead;
        }


        public List<string> GetHtmlTags(string html, string tag)
        {
            Regex regex = new Regex($"((<{tag})([^<]+)(</{tag}>))|((<{tag})([^>]+)([>]))", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline);
            MatchCollection matchCollection = regex.Matches(html);

            List<string> htmls = new List<string>();

            if (matchCollection.Count > 0)
            {
                foreach (Match subMatch in matchCollection)
                {
                    htmls.Add(subMatch.Groups[0].Value);
                }
            }
            return htmls;
        }

        public void SetContentId(long contentId)
        {
            this.ContentId = contentId;
        }
    }
}
